StatBlock_Durability = CreateFrame("Frame", "StatBlock_Durability")

StatBlock_Durability.obj = LibStub("LibDataBroker-1.1"):NewDataObject("Durability", {
	icon = "Interface\\Icons\\Trade_BlackSmithing",
	text = 0
})

local L = LibStub("AceLocale-3.0"):GetLocale("StatBlock_Durability")

local Gratuity = LibStub("LibGratuity-3.0")
local Abacus = LibStub("LibAbacus-3.0")
local Crayon = LibStub("LibCrayon-3.0")

local repairEntry
local itemStatus = {
	{ value = 0, max = 0, cost = 0, name = INVTYPE_HEAD, slot = GetInventorySlotInfo("HeadSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_SHOULDER, slot = GetInventorySlotInfo("ShoulderSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_CHEST, slot = GetInventorySlotInfo("ChestSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_WAIST, slot = GetInventorySlotInfo("WaistSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_LEGS, slot = GetInventorySlotInfo("LegsSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_FEET, slot = GetInventorySlotInfo("FeetSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_WRIST, slot = GetInventorySlotInfo("WristSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_HAND, slot = GetInventorySlotInfo("HandsSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_WEAPONMAINHAND, slot = GetInventorySlotInfo("MainHandSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_WEAPONOFFHAND, slot = GetInventorySlotInfo("SecondaryHandSlot") },
	{ value = 0, max = 0, cost = 0, name = INVTYPE_RANGED, slot = GetInventorySlotInfo("RangedSlot") },
}
local inventoryStatus = { value = 0, max = 0, cost = 0, name = INVENTORY_TOOLTIP }

local function percent(quotient, denominator)
	return quotient and denominator ~= 0 and (quotient / denominator) or 1
end

local GetContainerItemDurability = GetContainerItemDurability
local GetInventoryItemDurability = GetInventoryItemDurability

local ReputationDiscounts = {
	{ FACTION_STANDING_LABEL5, 0.95 },
	{ FACTION_STANDING_LABEL6, 0.9 },
	{ FACTION_STANDING_LABEL7, 0.85 },
	{ FACTION_STANDING_LABEL8, 0.8 },
}

local function durability(index, bag)
	if bag then
		if GetContainerItemInfo(bag, index) then
			local _,cost = Gratuity:SetBagItem(bag, index)
			local value, max = GetContainerItemDurability(bag, index)
			return value, max, cost
		end
	else
		if GetInventoryItemTexture("player", index) then
			local _, _ , cost = Gratuity:SetInventoryItem("player", index)
			local value, max = GetInventoryItemDurability(index)
			return value, max, cost
		end
	end
end

StatBlock_Durability:RegisterEvent("ADDON_LOADED")
function StatBlock_Durability:ADDON_LOADED(event, addon)
	if addon == "StatBlock_Durability" then
		SBDuraDB = SBDuraDB or {
			showMan = false,
			showAverage = false,
			showHealthy = false,
			autoRepair = true,
			useGuildMoney = false,
		}
		self.db = SBDuraDB
		self:UnregisterEvent("ADDON_LOADED")
		self.ADDON_LOADED = nil
	end
end

function StatBlock_Durability:DurabilityFrame_SetAlerts()
	if not self.db.showMan then
		DurabilityFrame:Hide()
	end
end

hooksecurefunc("DurabilityFrame_SetAlerts", function ()
	StatBlock_Durability:DurabilityFrame_SetAlerts()
end)


function StatBlock_Durability:PLAYER_LOGIN()
	self:RegisterEvent("PLAYER_UNGHOST")
	self:RegisterEvent("PLAYER_DEAD")
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("UPDATE_INVENTORY_ALERTS")
	self:RegisterEvent("MERCHANT_SHOW")
	self:RegisterEvent("MERCHANT_CLOSED")

	self:DurabilityFrame_SetAlerts()
	self:Update()
end

local lastUpdate
function StatBlock_Durability:UpdateBagData()
	local time, lastUpdate = GetTime(), self.lastUpdate
	if lastUpdate and time - lastUpdate < 1 then
		return
	end
	self.lastUpdate = time

	inventoryStatus.value = 0
	inventoryStatus.max = 0
	inventoryStatus.cost = 0

	local minStatus = 1.0
	for bag = 0, 4 do
		for slot = 1, GetContainerNumSlots(bag) do
			local value, max, cost = durability(slot, bag)
			local status = percent(value, max)
			if status and status < minStatus then
				minStatus = status

				if max ~= 0 and (not repairEntry or status < percent(repairEntry.value, repairEntry.max)) then
					repairEntry = inventoryStatus
				end

				inventoryStatus.value = value
				inventoryStatus.max = max
			end
			if cost then
				inventoryStatus.cost = inventoryStatus.cost + cost
			end
		end
	end
end

function StatBlock_Durability:PLAYER_UNGHOST()
	self:UpdateInventoryData()
	self:UpdateBagData()
	self:UpdateText()
end

StatBlock_Durability.PLAYER_DEAD = StatBlock_Durability.PLAYER_UNGHOST
StatBlock_Durability.PLAYER_REGEN_ENABLED = StatBlock_Durability.PLAYER_UNGHOST

function StatBlock_Durability:UpdateInventoryData()
	local minStatus = 1.0
	local minEntry

	for index = 1, 11 do
		local entry = itemStatus[index]
		local value, max, cost = durability(entry.slot)
		local status = percent(value, max)
		if status and status < minStatus then
			minStatus = status
			minEntry = entry
		end
		entry.value = value or 0
		entry.max = max or 0
		entry.cost = cost or 0
	end

	repairEntry = minEntry
end

function StatBlock_Durability:UPDATE_INVENTORY_ALERTS()
	self:UpdateInventoryData()
	self:UpdateText()
end

function StatBlock_Durability:RepairAllItems(guild)
	self:RegisterEvent("PLAYER_MONEY")
	RepairAllItems(guild)
	PlaySound("ITEM_REPAIR")
end

function StatBlock_Durability:PLAYER_MONEY()
	self:UnregisterEvent("PLAYER_MONEY")
	SetDesaturation(MerchantRepairAllIcon, 1)
	MerchantRepairAllButton:Disable()
	self:Update()
end

function StatBlock_Durability:MERCHANT_SHOW()
	if CanMerchantRepair() then
		local repairCost = GetRepairAllCost()
		local money = GetMoney()
		if money < repairCost then
			ChatFrame1:AddMessage(L["Cannot auto-repair. Your money: %s. Needed: %s"]:format(Abacus:FormatMoneyFull(money, true), Abacus:FormatMoneyFull(repairCost, true)))
		elseif repairCost > 0 then
			if self.db.autoRepair then
				self:RepairAllItems(self.db.useGuildMoney)
				ChatFrame1:AddMessage(L["Auto-repaired: %s"]:format(Abacus:FormatMoneyFull(repairCost)))
			elseif self.GetPopup then
				local popup = self:GetPopup()
				popup:SetValue(repairCost)
				popup:Show()
			end
		end
	end
	self:Update()
end

function StatBlock_Durability:MERCHANT_CLOSED()
	self:Update()
end

function StatBlock_Durability:Update()
	self:UpdateBagData()
	self:UpdateInventoryData()
	self:UpdateText()
end

function StatBlock_Durability:UpdateText()
	local status
	if self.db.showAverage then
		local value, max = inventoryStatus.value, inventoryStatus.max
		for i, item in pairs(itemStatus) do
			value = value + item.value
			max = max + item.max
		end
		status = percent(value, max)
	else
		status = percent(inventoryStatus.value, inventoryStatus.max)
		for i, item in pairs(itemStatus) do
			local p = percent(item.value, item.max)
			if p < status then status = p end
		end
	end
	self.obj.text = string.format("|cff%s%.0f%%|r", Crayon:GetThresholdHexColor(status), status * 100)
end

function StatBlock_Durability.obj.OnTooltipShow(tooltip)
	if not tooltip or not tooltip.AddLine or not tooltip.AddDoubleLine then return end
	local cost = 0
	tooltip:AddLine("StatBlock_Durability")
	for index, item in pairs(itemStatus) do
		if item.max > 0 then
			cost = cost + item.cost
			local status = percent(item.value, item.max)
			if status < 1 or StatBlock_Durability.db.showHealthy then
				local r, g, b = Crayon:GetThresholdColor(status)
				tooltip:AddDoubleLine(item.name, string.format("%.0f%%", status * 100), 1, 1, 1, r, g, b)
			end
		end
	end
	if inventoryStatus.max > 0 then
		local status = percent(inventoryStatus.value, inventoryStatus.max)
		if status < 1 or StatBlock_Durability.db.showHealthy then
			local r, g, b = Crayon:GetThresholdColor(status)
			tooltip:AddDoubleLine(inventoryStatus.name, string.format("%.0f%%", status * 100), 1, 1, 1, r, g, b)
		end
	end
	local value = 0
	local max = 0
	for i, item in pairs(itemStatus) do
		value = value + item.value
		max = max + item.max
	end
	local status = percent(value, max)
	local r, g, b = Crayon:GetThresholdColor(status)
	tooltip:AddDoubleLine(L["Percent"], string.format("%.0f%%", status * 100), 1, 1, 1, r, g, b)

	if cost > 0 then
		tooltip:AddDoubleLine(L["Repair cost"], Abacus:FormatMoneyFull(cost, true))

		for _, entry in ipairs(ReputationDiscounts) do
			tooltip:AddDoubleLine(entry[1], Abacus:FormatMoneyFull(cost * entry[2], true))
		end
	end
end

StatBlock_Durability:RegisterEvent("PLAYER_LOGIN")
StatBlock_Durability:SetScript("OnEvent", function (self, event, ...)
	local handler = self[event]
	if handler then return handler(self, event, ...) end
end)
